package game.util;

import game.games.rpg.Direction;
import game.gfx.ConsoleColor;
import game.util.sosc.ColorConverter;
import game.util.sosc.ConsoleColorConverter;
import game.util.sosc.DimensionConverter;
import game.util.sosc.IStringObjectStringConverter;
import game.util.sosc.PointConverter;
import game.util.sosc.ThrowableConverter;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

public class Util
{
    public static double nanoToSec(long nanotime)
    {
        double sec = (double) nanotime / (1000 * 1000 * 1000);
        return sec;
    }
    
    public static int byteArrayToInt(byte[] b)
    {
        return b[3] & 0xFF | (b[2] & 0xFF) << 8 | (b[1] & 0xFF) << 16 | (b[0] & 0xFF) << 24;
    }
    
    public static byte[] intToByteArray(int a)
    {
        return new byte[] { (byte) ((a >> 24) & 0xFF), (byte) ((a >> 16) & 0xFF), (byte) ((a >> 8) & 0xFF), (byte) (a & 0xFF) };
    }
    
    public static String readTxtFile(InputStream inputStream, String encoding) throws IOException
    {
        InputStreamReader in = null;
        try
        {
            StringBuilder result = new StringBuilder();
            int c = -1;
            in = new InputStreamReader(inputStream, encoding);
            while ((c = in.read()) >= 0)
            {
                result.append((char) c);
            }
            return result.toString();
        }
        finally
        {
            if (in != null)
            {
                in.close();
            }
        }
    }
    
    private static Map<Class<?>, IStringObjectStringConverter<?>> converters = new HashMap<>();
    static
    {
        converters.put(Color.class, new ColorConverter());
        converters.put(ConsoleColor.class, new ConsoleColorConverter());
        converters.put(Direction.class, new IStringObjectStringConverter<Direction>()
        {
            @Override
            public Direction toObject(String string)
            {
                return Direction.valueOf(string);
            }

            @Override
            public String toString(Direction object)
            {
                return object.toString();
            }
        });
        // Java Classes
        converters.put(Dimension.class, new DimensionConverter());
        converters.put(Point.class, new PointConverter());
        converters.put(Throwable.class, new ThrowableConverter());
        converters.put(Integer.class, new IStringObjectStringConverter<Integer>()
        {
            @Override
            public Integer toObject(String string)
            {
                return Integer.valueOf(string);
            }
            @Override
            public String toString(Integer object)
            {
                return object.toString();
            }
        });
        converters.put(Long.class, new IStringObjectStringConverter<Long>()
        {
            @Override
            public Long toObject(String string)
            {
                return Long.valueOf(string);
            }
            @Override
            public String toString(Long object)
            {
                return object.toString();
            }
        });
        converters.put(Character.class, new IStringObjectStringConverter<Character>()
        {
            @Override
            public Character toObject(String string)
            {
                return string.charAt(0);
            }
            @Override
            public String toString(Character object)
            {
                return object.toString();
            }
        });
        converters.put(Boolean.class, new IStringObjectStringConverter<Boolean>()
        {
            @Override
            public Boolean toObject(String string)
            {
                return Boolean.valueOf(string);
            }
            @Override
            public String toString(Boolean object)
            {
                return object.toString();
            }
        });
        converters.put(String.class, new IStringObjectStringConverter<String>()
        {
            @Override
            public String toObject(String string)
            {
                return string;
            }
            @Override
            public String toString(String object)
            {
                return object;
            }
        });
        converters.put(Class.class, new IStringObjectStringConverter<Class<?>>()
        {
            @Override
            public Class<?> toObject(String string)
            {
                Class<?> clazz = null;
                try
                {
                    clazz = Class.forName(string);
                }
                catch (ClassNotFoundException ex)
                {
                    Logger.warn(ex);
                }
                return clazz;
            }
            @Override
            public String toString(Class<?> object)
            {
                return object.getCanonicalName();
            }
        });
        
    }
    
    public static <T> String toString(T object)
    {
        if (object == null)
        {
            return "NULL";
        }
        @SuppressWarnings("unchecked")
        IStringObjectStringConverter<T> converter = (IStringObjectStringConverter<T>) converters.get(object.getClass()); 
        if (converter == null)
        {
            Logger.warn("No converter found: ", object.getClass());
            return object.toString();
        }
        return converter.toString(object);
    }

    public static <T> T toObject(String value, Class<T> clazz)
    {
        if ("NULL".equals(value))
        {
            return null;
        }
        @SuppressWarnings("unchecked")
        IStringObjectStringConverter<T> converter =  (IStringObjectStringConverter<T>) converters.get(clazz);
        if (converter == null)
        {
            Logger.warn("No converter found: ", clazz);
            return null;
        }
        return converter.toObject(value);
    }
}
